/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.common.utility;

import com.inspur.edp.web.common.constant.WebCommonExceptionConstant;
import com.inspur.edp.web.common.constant.WebCommonI18nMsgConstant;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.entity.CommandExecutedResult;
import com.inspur.edp.web.common.logger.WebLogger;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;

import java.io.IOException;
import java.util.Arrays;

/**
 * 命令行参数
 *
 * @author noah
 */
public class CommandLineUtility {
    private CommandLineUtility() {
    }

    public static boolean runCommand(String[] commands) {
        return runCommand(commands, true);
    }

    public static boolean runCommand(String[] commands, boolean isWait) {
        String command = String.join(" && ", commands);
        String errorMsg = runCommand(command, isWait);
        return StringUtils.isNotEmpty(errorMsg);
    }

    /**
     * 执行命令
     *
     * @param command 待执行命令
     */
    public static String runCommand(String command) {
        return runCommand(command, true);
    }

    public static CommandExecutedResult runCommandWithoutThrows(String command) {
        StringBuffer errorSB = new StringBuffer();
        StringBuffer outputSB = new StringBuffer();
        return executeCommandWithOutput(command, errorSB, outputSB);
    }

    /**
     * 执行命令
     *
     * @param command 待执行命令
     * @param isWait  是否等待返回结果
     */
    public static String runCommand(String command, boolean isWait) {

        StringBuffer errorSB = new StringBuffer();
        String errorMessage = executeCommand(command, errorSB);
        // 如果出现编译错误 那么通过异常的方式将错误信息进行抛出
        // 增加自定义异常抛出 进行特定异常捕获
        if (!StringUtility.isNullOrEmpty(errorMessage)) {
            throw new WebCustomException(errorMessage);
//            throw new WebCustomException(command + " executed failed!<br>" + errorMessage);
        }

        // 如果存在输出异常 那么不再继续执行
        if (!StringUtility.isNullOrEmpty(errorSB.toString())) {
            throw new WebCustomException(errorSB.toString());
//            throw new WebCustomException(command + " executed failed!<br>" + errorSB);
        }

        return errorMessage;
    }

    /**
     * 执行具体命令
     *
     * @param command 具体命令参数
     * @param errorSB 错误信息返回
     * @return
     */
    public static String executeCommand(String command, StringBuffer errorSB) {
        String errorMessage = "";
        try {
            WebLogger.Instance.info(command, CommandLineUtility.class.getName());
            Process process = getProcessWithOs(command);

            CommandExecuteInterceptor errorCommandInterceptor = new CommandExecuteInterceptor(process.getErrorStream(), errorSB, null, true);
            CommandExecuteInterceptor inputCommandInterceptor = new CommandExecuteInterceptor(process.getInputStream(), errorSB, null, false);

            // 设置配置子线程的异常捕获器 不能进行全局线程异常捕获，会影响其他线程的异常抛出，只限定当前启动的线程异常信息
            errorCommandInterceptor.setUncaughtExceptionHandler(new WebThreadUncaughtExceptionHandler());
            inputCommandInterceptor.setUncaughtExceptionHandler(new WebThreadUncaughtExceptionHandler());

            errorCommandInterceptor.start();
            inputCommandInterceptor.start();

            int waitCode = process.waitFor();
            if (waitCode != 0) {
                WebLogger.Instance.info("进程执行完毕", CommandLineUtility.class.getName());
            }
        } catch (Exception e) {
            WebLogger.Instance.error(e);
            errorMessage = e.getMessage() + Arrays.toString(e.getStackTrace());
        }
        return errorMessage;
    }

    public static CommandExecutedResult executeCommandWithOutput(String command, StringBuffer errorSB, StringBuffer outputSB) {
        CommandExecutedResult result = new CommandExecutedResult();
        result.setCommand(command);
        String errorMessage = "";
        try {
            WebLogger.Instance.info(command, CommandLineUtility.class.getName());
            Process process = getProcessWithOs(command);

            CommandExecuteInterceptor errorCommandInterceptor = new CommandExecuteInterceptor(process.getErrorStream(), errorSB, outputSB, true);
            CommandExecuteInterceptor inputCommandInterceptor = new CommandExecuteInterceptor(process.getInputStream(), errorSB, outputSB, false);

            // 设置配置子线程的异常捕获器 不能进行全局线程异常捕获，会影响其他线程的异常抛出，只限定当前启动的线程异常信息
            errorCommandInterceptor.setUncaughtExceptionHandler(new WebThreadUncaughtExceptionHandler());
            inputCommandInterceptor.setUncaughtExceptionHandler(new WebThreadUncaughtExceptionHandler());

            errorCommandInterceptor.start();
            inputCommandInterceptor.start();

            int waitCode = process.waitFor();
            result.setExitCode(waitCode);
            errorMessage = errorSB.toString();
        } catch (Exception e) {
            result.setExitCode(-1);
            WebLogger.Instance.error(e);
            errorMessage = e.getMessage() + Arrays.toString(e.getStackTrace());
        }
        result.setErrorInfo(errorMessage);
        result.setOutputInfo(outputSB.toString());
        return result;
    }

    /**
     * 获取适应于不同操作系统的Process
     * @param command
     * @return
     * @throws IOException
     */
    public static Process getProcessWithOs(String command) throws IOException {
        Process process = null;
        String updateCommand = command;
        if (SystemUtils.IS_OS_WINDOWS) {
            updateCommand = "cmd.exe" + " /C" + " " + command;
            process = Runtime.getRuntime().exec(updateCommand);
        } else if (SystemUtils.IS_OS_UNIX) {
            updateCommand = command;
            process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", updateCommand});
        }
        if (updateCommand == null) {
            throw new WebCustomException(WebCommonExceptionConstant.WEB_COMMON_ERROR_0008);
        }
        return process;
    }


    /**
     * 判断是否包含错误描述信息
     *
     * @param message
     * @return
     */
    public static boolean checkHasError(String message) {
        if (StringUtils.isEmpty(message)) {
            return false;
        }
        // 表示以error开头
        return message.toLowerCase().contains("error:") || message.toLowerCase().contains("rollup build failed") || message.toLowerCase().contains("build error") || message.toLowerCase().contains("npm err!");
    }

    private static String getCommandLineToolName() {
        if (SystemUtils.IS_OS_WINDOWS) {
            return "cmd.exe";
        } else if (SystemUtils.IS_OS_UNIX) {
            return "/bin/bash";
        }

        throw new WebCustomException(WebCommonExceptionConstant.WEB_COMMON_ERROR_0009);
    }
}



